﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Walson.Windows.Forms
{
    public partial class UavPfd : Control
    {
        private float _Roll = 0;
        public float Roll 
        {
            get => _Roll; 
            set
            {
                _Roll = value; 

                while(_Roll>180)
                {
                    _Roll = 360 - Roll;
                }

                while(_Roll<-180)
                {
                    _Roll = -360 - _Roll;
                }

                this.Invalidate(); 
            }
        }

        private float _Pitch = 0;
        public float Pitch 
        {
            get => _Pitch; 
            set
            { 
                _Pitch = value;

                while (_Pitch > 90)
                {
                    _Pitch = 180 - _Pitch;
                }

                while (_Pitch < -90)
                {
                    _Pitch = -180 - _Pitch;
                }

                this.Invalidate(); 
            }
        }

        private float _Heading = 0;
        public float Heading 
        {
            get => _Heading; 
            set
            { 
                _Heading = value;
                while (_Heading > 360)
                    _Heading -= 360;
                while (_Heading < 0)
                    _Heading += 360;
                this.Invalidate();
            }
        }

        private bool _UseAirSpeed = true;
        public bool UseAirSpeed { get => _UseAirSpeed;set { _UseAirSpeed = value;this.Invalidate(); } }

        private float _AirSpeed = 0;
        public float AirSpeed { get => _AirSpeed; set { _AirSpeed = value;this.Invalidate(); } }

        private float _GroundSpeed = 0;
        public float GroundSpeed { get => _GroundSpeed; set { _GroundSpeed = value; this.Invalidate(); } }

        public float Speed => UseAirSpeed ? _AirSpeed : _GroundSpeed;

        private float _VerticalSpeed = 0;
        public float VerticalSpeed { get => _VerticalSpeed; set { _VerticalSpeed = value; this.Invalidate(); } }


        private bool _UseRelativeAltitude = true;
        public bool UseRelativeAltitude { get => _UseRelativeAltitude; set { _UseRelativeAltitude = value; this.Invalidate(); } }

        private float _MslAltitude = 0;
        public float MslAltitude { get => _MslAltitude; set { _MslAltitude = value;this.Invalidate(); } }

        public float AbsoluteAltitude => _MslAltitude + _RelativeAltitude;

        private float _RelativeAltitude = 0;
        public float RelativeAltitude { get => _RelativeAltitude; set { _RelativeAltitude = value; this.Invalidate(); } }

        public float Altitude => UseRelativeAltitude ? _RelativeAltitude : _MslAltitude;

        private Color[] _SkyColors = new Color[2] { Color.Blue, Color.LightBlue };
        public Color[] SkyColors { get => _SkyColors; set { _SkyColors = value;this.Invalidate(); } }

        private Color[] _GroundColors = new Color[2] { Color.FromArgb(0x9b, 0xb8, 0x24), Color.FromArgb(65, 79, 7) };
        public Color[] GroundColors { get => _GroundColors; set { _GroundColors = value; this.Invalidate(); } }

        private float _FontScaleFacotr = 1 / 600.0f;
        private float _SmallFontSize=20, _MediumFontSize=25, _LargeFontSize=40;
        private float _ActualSmallFontSize, _ActualMediumFontSize, _ActualLargeFontSize;
        public float SmallFontSize { get => _SmallFontSize; set { _SmallFontSize = value; _ActualSmallFontSize = _MinLength * value * _FontScaleFacotr ; InitParams(); this.Invalidate(); } }
        public float MediumFontSize { get => _MediumFontSize; set { _MediumFontSize = value; _ActualMediumFontSize = _MinLength * value * _FontScaleFacotr ; InitParams(); this.Invalidate(); } }
        public float LargeFontSize { get => _LargeFontSize; set { _LargeFontSize = value; _ActualLargeFontSize = _MinLength * value * _FontScaleFacotr; InitParams(); this.Invalidate(); } }

        private bool _MiniMode = false;
        public bool MiniMode { get => _MiniMode; set { _MiniMode = value; InitParams(); this.Invalidate(); } }

        private Font _Font = new Font("微软雅黑", 10, FontStyle.Bold);
        public override Font Font { get => _Font; set { _Font = value; InitParams(); this.Invalidate(); } }

        private bool _DarkTheme = false;
        public bool DarkTheme { get => _DarkTheme;set { _DarkTheme = value;ChangeTheme(); InitParams(); this.Invalidate(); } }

        private bool _RoundCorner = true;
        public bool RoundCorner { get => _RoundCorner; set { _RoundCorner = value;this.Invalidate(); } }

        float _MinLength,_MaxLength;

        Bitmap
            _PitchAndRollBmp,
            _AltitudeBmp,
            _SpeedBmp,
            _CompassBmp,
            _VerticalSpeedBmp;

        PointF
            _PitchAndRollLocation,
            _AltitudeLocation,
            _SpeedLocation,
            _CompassLocation,
            _VerticalSpeedLocation;

        float
            _HalfHeight_PitchAndRoll,
            _HalfHeight_Altitude,
            _HalfHeight_Speed,
            _HalfHeight_Compass,
            _HalfHeigth_VerticalSpeed,
            _HalfWidth_PitchAndRoll,
            _HalfWidth_Altitude,
            _HalfWidth_Speed,
            _HalfWidth_Compass,
            _HalfWidth_VerticalSpeed;

        Font
            _SmallFont,
            _MediumFont,
            _LargeFont;


        float
            _PitchIndicatorInterval,
            _AltitudeIndicatorInterval,
            _SpeedIndicatorInterval,
            _CompassIndicatorInterval;

        Pen
            _WhiteIndicatorPen = new Pen(Brushes.White, 2),
            _GreenIndicatorPen = new Pen(Brushes.DarkGreen, 2),
            _RedIndicatorPen = new Pen(Brushes.OrangeRed, 3);

        LinearGradientBrush
            _SkyBrush,
            _GroundBrush;

        SolidBrush
            RedBrush = new SolidBrush(Color.Red),
            YellowBrush = new SolidBrush(Color.Yellow);

        Color _PanelColor = Color.FromArgb(128, 0, 0, 0);
        SolidBrush _PanelBrush = new SolidBrush(Color.FromArgb(128, 0, 0, 0));


        public UavPfd()
        {
            InitializeComponent();
            this.DoubleBuffered = true;
            this.SizeChanged += (ss, ee) => InitParams();
            InitParams();
        }

        //public UavPfd(IContainer container)
        //{
        //    container.Add(this);

        //    InitializeComponent();
        //}
        private void ChangeTheme()
        {
            if (_DarkTheme)
            {
                _GroundColors = new Color[2] { Color.FromArgb(99, 57, 24), Color.FromArgb(99, 57, 24) };
                _SkyColors = new Color[2] { Color.FromArgb(41, 156, 239), Color.FromArgb(41, 156, 239) };
                _PanelColor = Color.FromArgb(128, Color.LightGray);
                _PanelBrush = new SolidBrush(_PanelColor);
            }
            else
            {
                _GroundColors = new Color[2] { Color.FromArgb(0x9b, 0xb8, 0x24), Color.FromArgb(65, 79, 7) };
                _SkyColors = new Color[2] { Color.Blue, Color.LightBlue };
                _PanelColor = Color.FromArgb(128, Color.LightGray);
                _PanelBrush = new SolidBrush(_PanelColor);
            }
        }

        private void InitParams()
        {
            _MinLength = Math.Min(this.Width, this.Height);
            _MaxLength = Math.Max(this.Width, this.Height);

            if (_MinLength <= 0)
                return;

            // 字体
            _ActualSmallFontSize = _MinLength * SmallFontSize * _FontScaleFacotr;
            _ActualMediumFontSize = _MinLength * MediumFontSize * _FontScaleFacotr;
            _ActualLargeFontSize = _MinLength * LargeFontSize * _FontScaleFacotr;

            _SmallFont = new Font(this.Font.Name, _ActualSmallFontSize, this.Font.Style);
            _MediumFont = new Font(this.Font.Name, _ActualMediumFontSize, this.Font.Style);
            _LargeFont = new Font(this.Font.Name, _ActualLargeFontSize, this.Font.Style);

            // Pitch and roll
            if(MiniMode)
            {
                _PitchAndRollBmp = new Bitmap((int)(_MinLength * 0.9f), (int)(_MinLength*0.9f));
                _PitchAndRollLocation = new PointF((this.Width - _MinLength * 0.9f) / 2, (this.Height - _MinLength * 0.9f) / 2);

                int max = Math.Max(_PitchAndRollBmp.Width, _PitchAndRollBmp.Height);

                RectangleF rect = new RectangleF(0, 0, max * 1.414f, max * 1.414f);
                _SkyBrush = new LinearGradientBrush(rect, _SkyColors[0], _SkyColors[1],90.0f);
                _GroundBrush = new LinearGradientBrush(rect, _GroundColors[0], _GroundColors[1], 90.0f);
            }
            else
            {
                //_PitchAndRollBmp = new Bitmap((int)(this.Width * 0.58f), (int)(this.Height * 0.75f));
                //_PitchAndRollLocation = new PointF(this.Width * 0.16f, this.Height * 0.05f);
                _PitchAndRollBmp = new Bitmap((int)(this.Width), (int)(this.Height));
                _PitchAndRollLocation = new PointF(0,0);

                float max = Math.Max(_PitchAndRollBmp.Width, _PitchAndRollBmp.Height)*1.5f;
                RectangleF rect = new RectangleF(0, 0, max*1.5f, max*1.5f);
                _SkyBrush = new LinearGradientBrush(rect, _SkyColors[0], _SkyColors[1], 90.0f);
                _GroundBrush = new LinearGradientBrush(rect, _GroundColors[0], _GroundColors[1], 90.0f);
            }

            // 速度相关参数
            _SpeedBmp = new Bitmap((int)(this.Width * 0.15f), (int)(this.Height * 0.84f));
            _SpeedLocation = new PointF(0, this.Height * 0.08f);

            // 高度计相关参数
            _AltitudeBmp = new Bitmap((int)(this.Width * 0.15f), (int)(this.Height * 0.84f));
            _AltitudeLocation = new PointF(this.Width * 0.75f, this.Height * 0.08f);

            // 垂直速度相关参数
            _VerticalSpeedBmp = new Bitmap((int)(this.Width * 0.11f), (int)(this.Height * 0.7));
            _VerticalSpeedLocation = new PointF(this.Width * 0.91f, this.Height * 0.15f);

            // 罗盘相关参数
            _CompassBmp = new Bitmap((int)(this.Width * 0.58), (int)(this.Height * 0.14));
            _CompassLocation = new PointF(this.Width * 0.16f, this.Height * 0.78f);


            // 各个组件数值指示器横线之间的间隔
            _PitchIndicatorInterval = _MinLength / 90.0f;
            _SpeedIndicatorInterval = _MinLength / 15.0f;
            _AltitudeIndicatorInterval = _MinLength / 15.0f;
            _CompassIndicatorInterval = _MinLength / 10.0f;


            // 各个部件的半高、半长
            _HalfHeight_PitchAndRoll = _PitchAndRollBmp.Height / 2;
            _HalfHeight_Altitude = _AltitudeBmp.Height / 2;
            _HalfHeight_Speed = _SpeedBmp.Height / 2;
            _HalfHeight_Compass = _CompassBmp.Height / 2;
            _HalfWidth_PitchAndRoll = _PitchAndRollBmp.Width / 2;
            _HalfWidth_Altitude = _AltitudeBmp.Width / 2;
            _HalfWidth_Speed = _SpeedBmp.Width / 2;
            _HalfWidth_Compass = _CompassBmp.Width / 2;
        }


        private void DrawPitchAndRoll()
        {
            int width = _PitchAndRollBmp.Width, height = _PitchAndRollBmp.Height;
            float max = Math.Max(_PitchAndRollBmp.Width, _PitchAndRollBmp.Height)*1.5f;
            float min = Math.Min(width, height);
            //MessageBox.Show(min.ToString());
            float
                centerX = ( _SpeedBmp.Width + _AltitudeLocation.X) / 2;
            float centerZoneWidth =( _AltitudeLocation.X - _SpeedBmp.Width)*0.9f;
            min = Math.Min(min, centerZoneWidth);
            //MessageBox.Show(min.ToString());
            using (Graphics g = Graphics.FromImage(_PitchAndRollBmp))
            {
                g.SmoothingMode = SmoothingMode.AntiAlias;
                g.InterpolationMode = InterpolationMode.NearestNeighbor;
                g.CompositingMode = CompositingMode.SourceOver;
                g.CompositingQuality = CompositingQuality.HighSpeed;
                g.PixelOffsetMode = PixelOffsetMode.HighSpeed;
                g.TextRenderingHint = TextRenderingHint.SystemDefault;

                g.Clear(Color.Red);

                // 绘制天地
                // 设置平移
                //g.TranslateTransform(_HalfWidth_PitchAndRoll, _HalfHeight_PitchAndRoll);
                g.TranslateTransform(centerX, _HalfHeight_PitchAndRoll);
                // 设置旋转
                if (_Roll != 0)
                    g.RotateTransform(0 - _Roll);
                if (_Pitch != 0)
                    g.TranslateTransform(0, _Pitch * _PitchIndicatorInterval);

                g.FillRectangle(_GroundBrush, -max/2, 0, max, max*2);
                g.FillRectangle(_SkyBrush, -max/2, -max*2, max, max*2 );
                g.DrawLine(_WhiteIndicatorPen, -width, 0, width * 2, 0);

                // 绘制俯仰刻度
                int
                    start = (int)_Pitch + 15,
                    end = (int)_Pitch - 15;
                float startPos = 0, endPos;
                float y;
                bool b;

                if (start > 90)
                    start = 90;
                if (end < -90)
                    end = -90;
                for (int i = start; i >= end; i -= 5)
                {
                    y = 0 - i * _PitchIndicatorInterval;

                    string str = i.ToString();
                    SizeF txtSize = g.MeasureString(str, _SmallFont);
                    b = i % 10 == 0;
                    if (b)
                    {
                        startPos = -min * 0.1f;
                    }
                    else
                    {
                        startPos = -min * 0.05f;
                    }

                    endPos = 0 - startPos;
                    if (i == 0)
                        g.DrawLine(_GreenIndicatorPen, startPos, y, endPos, y);
                    else
                        g.DrawLine(_WhiteIndicatorPen, startPos, y, endPos, y);

                    if(b)
                    {
                        StringFormat format = StringFormat.GenericTypographic;
                        var rectLeft = new RectangleF(startPos - txtSize.Width - 5, y - txtSize.Height / 2, txtSize.Width, txtSize.Height);
                        var rectRight = new RectangleF(endPos + 5, y - txtSize.Height / 2, txtSize.Width, txtSize.Height);
                        float size = g.DpiY * _SmallFont.SizeInPoints / 72; ;
                        GraphicsPath path = new GraphicsPath();
                        path.AddString(str, _SmallFont.FontFamily, (int)_SmallFont.Style, size, rectLeft, format);
                        path.AddString(str, _SmallFont.FontFamily, (int)_SmallFont.Style, size, rectRight, format);
                        g.DrawPath(new Pen(Color.Black, 2), path);
                        g.FillPath(Brushes.White, path);
                    }
                }

                // 绘制滚转刻度
                double r1, r2, r3;
                r1 = min * 0.45;
                r2 = r1 * 0.94;
                r3 = r1 * 1.2;

                Rectangle rect;
                g.TranslateTransform(0, -_Pitch * _PitchIndicatorInterval);
                rect = new Rectangle((int)-r2, (int)(-r2), (int)r2 * 2, (int)r2 * 2);
                g.DrawArc(_WhiteIndicatorPen, rect, -150, 120);
                g.RotateTransform(120);
                for (int i = -6; i <= 6; i++)
                {
                    g.DrawLine(_WhiteIndicatorPen, 0, (float)r1, 0, (float)r2);

                    string str = Math.Abs(i * 10).ToString();
                    SizeF txtSize = g.MeasureString(str, _SmallFont);
                    var rectf = new RectangleF(-txtSize.Width / 2 + 5, (float)(-r3), txtSize.Width, txtSize.Height);

                    if (i % 2 == 0)
                    {
                        g.RotateTransform(180);
                        StringFormat format = StringFormat.GenericTypographic;

                        GraphicsPath path = new GraphicsPath();

                        float size = g.DpiY * _SmallFont.SizeInPoints / 72;
                        path.AddString(str, _SmallFont.FontFamily, (int)_SmallFont.Style, size, rectf, format);

                        g.DrawPath(new Pen(Color.Black, 2), path);
                        g.FillPath(Brushes.White, path);
                        g.RotateTransform(190);
                    }
                    else
                        g.RotateTransform(10);
                }

                // 在横滚角度的基础上旋转了250°，转回去再画三角
                g.RotateTransform(-250+_Roll);
                if (_Roll >= -70 && _Roll <= 70)
                {
                    // 绘制坡度的指示三角
                    PointF[] triangle = new PointF[4];
                    float triangleWidth = min * 0.050f;
                    float triangleHalfWidth = triangleWidth / 2;
                    float triangleHeight = (float)(triangleHalfWidth * Math.Tan(Math.PI / 3));
                    float triangleOffset = (float)-r2 + 5;//topPosY + height * 0.13f;

                    triangle[0] = new PointF(0, triangleOffset);
                    triangle[1] = new PointF(-triangleHalfWidth, triangleOffset + triangleHeight);
                    triangle[2] = new PointF(triangleHalfWidth, triangleOffset + triangleHeight);
                    triangle[3] = new PointF(0, triangleOffset);
                    g.DrawLines(_WhiteIndicatorPen, triangle);
                    g.FillPolygon(Brushes.Red, triangle);
                }

                // 水平指示器
                // 中间的小方块
                PointF[] centerIndicator = new PointF[5];
                int squareWidth = (int)(min * 0.014f);
                //Rectangle rect = new Rectangle(-squareWidth, 0, squareWidth * 2, squareWidth * 2);
                centerIndicator[0] = new PointF(squareWidth, 0);
                centerIndicator[1] = new PointF(squareWidth, squareWidth * 2);
                centerIndicator[2] = new PointF(-squareWidth, squareWidth * 2);
                centerIndicator[3] = new PointF(-squareWidth, 0);
                centerIndicator[4] = new PointF(squareWidth, 0);
                g.FillPolygon(Brushes.Maroon, centerIndicator);
                g.DrawLines(_WhiteIndicatorPen, centerIndicator);

                // 绘制水平指示
                float centerIndicatorWidth = min * 0.1f;
                float centerIndicatorGap = min * 0.2f;
                float barWidth = min * 0.015f;
                float centerIndicatorHeight = min * 0.05f;
                centerIndicator = new PointF[7];
                centerIndicator[0] = new PointF(-centerIndicatorGap, 0);
                centerIndicator[1] = new PointF(-centerIndicatorWidth - centerIndicatorGap, 0);
                centerIndicator[2] = new PointF(-centerIndicatorWidth - centerIndicatorGap, barWidth);
                centerIndicator[3] = new PointF(-centerIndicatorGap - barWidth, barWidth);
                centerIndicator[4] = new PointF(-centerIndicatorGap - barWidth, centerIndicatorHeight);
                centerIndicator[5] = new PointF(-centerIndicatorGap, centerIndicatorHeight);
                centerIndicator[6] = new PointF(-centerIndicatorGap, 0);
                g.FillPolygon(Brushes.Maroon, centerIndicator);
                g.DrawLines(_WhiteIndicatorPen, centerIndicator);

                centerIndicator[0] = new PointF(centerIndicatorGap, 0);
                centerIndicator[1] = new PointF(centerIndicatorWidth + centerIndicatorGap, 0);
                centerIndicator[2] = new PointF(centerIndicatorWidth + centerIndicatorGap, barWidth);
                centerIndicator[3] = new PointF(centerIndicatorGap + barWidth, barWidth);
                centerIndicator[4] = new PointF(centerIndicatorGap + barWidth, centerIndicatorHeight);
                centerIndicator[5] = new PointF(centerIndicatorGap, centerIndicatorHeight);
                centerIndicator[6] = new PointF(centerIndicatorGap, 0);
                g.FillPolygon(Brushes.Maroon, centerIndicator);
                g.DrawLines(_WhiteIndicatorPen, centerIndicator);
                g.ResetTransform();

                //if (RoundCorner)
                //{
                //    // 设置外形为圆角矩形
                //    GraphicsPath roundRect = new GraphicsPath();
                //    // 绘制圆角
                //    rect = new Rectangle(0, 0, width, height);
                //    int radius = (int)(_MinLength / 5);
                //    //顶端 
                //    roundRect.AddLine(rect.Left + radius - 1, rect.Top - 1, rect.Right - radius, rect.Top - 1);
                //    //右上角 
                //    roundRect.AddArc(rect.Right - radius, rect.Top - 1, radius, radius, 270, 90);
                //    //右边 
                //    roundRect.AddLine(rect.Right, rect.Top + radius, rect.Right, rect.Bottom - radius);
                //    //右下角
                //    roundRect.AddArc(rect.Right - radius, rect.Bottom - radius, radius, radius, 0, 90);
                //    //底边 
                //    roundRect.AddLine(rect.Right - radius, rect.Bottom, rect.Left + radius, rect.Bottom);
                //    //左下角 
                //    roundRect.AddArc(rect.Left - 1, rect.Bottom - radius, radius, radius, 90, 90);
                //    //左边 
                //    roundRect.AddLine(rect.Left - 1, rect.Top + radius, rect.Left - 1, rect.Bottom - radius);
                //    //左上角 
                //    roundRect.AddArc(rect.Left - 1, rect.Top - 1, radius, radius, 180, 90);
                //    // 外框
                //    roundRect.AddRectangle(rect);
                //    g.FillRegion(new SolidBrush(this.BackColor), new Region(roundRect));
                //}
            }
        }

        private void DrawMiniPitchAndRoll()
        {
            int width = _PitchAndRollBmp.Width, height = _PitchAndRollBmp.Height;
            float max = Math.Max(_PitchAndRollBmp.Width, _PitchAndRollBmp.Height) * 1.5f;
            float min = Math.Min(width, height);
            using (Graphics g = Graphics.FromImage(_PitchAndRollBmp))
            {
                g.SmoothingMode = SmoothingMode.AntiAlias;
                g.InterpolationMode = InterpolationMode.NearestNeighbor;
                g.CompositingMode = CompositingMode.SourceOver;
                g.CompositingQuality = CompositingQuality.HighSpeed;
                g.PixelOffsetMode = PixelOffsetMode.HighSpeed;
                g.TextRenderingHint = TextRenderingHint.SystemDefault;

                g.Clear(Color.Red);

                // 绘制天地
                // 设置平移
                g.TranslateTransform(_HalfWidth_PitchAndRoll, _HalfHeight_PitchAndRoll);
                // 设置旋转
                if (_Roll != 0)
                    g.RotateTransform(0 - _Roll);
                if (_Pitch != 0)
                    g.TranslateTransform(0, _Pitch * _PitchIndicatorInterval);

                g.FillRectangle(_GroundBrush, -max / 2, 0, max, max * 2);
                g.FillRectangle(_SkyBrush, -max / 2, -max * 2, max, max * 2);
                g.DrawLine(_WhiteIndicatorPen, -width, 0, width * 2, 0);

                // 绘制俯仰刻度
                int
                    start = (int)_Pitch + 15,
                    end = (int)_Pitch - 15;
                float startPos = 0, endPos;
                float y;
                bool b;

                if (start > 90)
                    start = 90;
                if (end < -90)
                    end = -90;
                for (int i = start; i >= end; i -= 5)
                {
                    y = 0 - i * _PitchIndicatorInterval;

                    string str = i.ToString();
                    SizeF txtSize = g.MeasureString(str, _SmallFont);
                    b = i % 10 == 0;
                    if (b)
                    {
                        startPos = -min * 0.1f;
                    }
                    else
                    {
                        startPos = -min * 0.05f;
                    }

                    endPos = 0 - startPos;
                    if (i == 0)
                        g.DrawLine(_GreenIndicatorPen, startPos, y, endPos, y);
                    else
                        g.DrawLine(_WhiteIndicatorPen, startPos, y, endPos, y);

                    if (b)
                    {
                        StringFormat format = StringFormat.GenericTypographic;
                        var rectLeft = new RectangleF(startPos - txtSize.Width - 5, y - txtSize.Height / 2, txtSize.Width, txtSize.Height);
                        var rectRight = new RectangleF(endPos + 5, y - txtSize.Height / 2, txtSize.Width, txtSize.Height);
                        float size = g.DpiY * _SmallFont.SizeInPoints / 72; ;
                        GraphicsPath path = new GraphicsPath();
                        path.AddString(str, _SmallFont.FontFamily, (int)_SmallFont.Style, size, rectLeft, format);
                        path.AddString(str, _SmallFont.FontFamily, (int)_SmallFont.Style, size, rectRight, format);
                        g.DrawPath(new Pen(Color.Black, 2), path);
                        g.FillPath(Brushes.White, path);
                    }
                }

                // 绘制滚转刻度
                double r1, r2, r3;
                r1 = _MinLength * 0.35;
                r2 = r1 * 0.94;
                r3 = r1 * 1.2;

                Rectangle rect;
                g.TranslateTransform(0, -_Pitch * _PitchIndicatorInterval);
                rect = new Rectangle((int)-r2, (int)(-r2), (int)r2 * 2, (int)r2 * 2);
                g.DrawArc(_WhiteIndicatorPen, rect, -150, 120);
                g.RotateTransform(120);
                for (int i = -6; i <= 6; i++)
                {
                    g.DrawLine(_WhiteIndicatorPen, 0, (float)r1, 0, (float)r2);

                    string str = Math.Abs(i * 10).ToString();
                    SizeF txtSize = g.MeasureString(str, _SmallFont);
                    var rectf = new RectangleF(-txtSize.Width / 2 + 5, (float)(-r3), txtSize.Width, txtSize.Height);

                    if (i % 2 == 0)
                    {
                        g.RotateTransform(180);
                        StringFormat format = StringFormat.GenericTypographic;

                        GraphicsPath path = new GraphicsPath();

                        float size = g.DpiY * _SmallFont.SizeInPoints / 72;
                        path.AddString(str, _SmallFont.FontFamily, (int)_SmallFont.Style, size, rectf, format);

                        g.DrawPath(new Pen(Color.Black, 2), path);
                        g.FillPath(Brushes.White, path);
                        g.RotateTransform(190);
                    }
                    else
                        g.RotateTransform(10);
                }

                // 在横滚角度的基础上旋转了250°，转回去再画三角
                g.RotateTransform(-250 + _Roll);
                if (_Roll >= -70 && _Roll <= 70)
                {
                    // 绘制坡度的指示三角
                    PointF[] triangle = new PointF[4];
                    float triangleWidth = width * 0.050f;
                    float triangleHalfWidth = triangleWidth / 2;
                    float triangleHeight = (float)(triangleHalfWidth * Math.Tan(Math.PI / 3));
                    float triangleOffset = (float)-r2 + 5;//topPosY + height * 0.13f;

                    triangle[0] = new PointF(0, triangleOffset);
                    triangle[1] = new PointF(-triangleHalfWidth, triangleOffset + triangleHeight);
                    triangle[2] = new PointF(triangleHalfWidth, triangleOffset + triangleHeight);
                    triangle[3] = new PointF(0, triangleOffset);
                    g.DrawLines(_WhiteIndicatorPen, triangle);
                    g.FillPolygon(Brushes.Red, triangle);
                }

                // 水平指示器
                float x1 = -_HalfWidth_PitchAndRoll * 0.65f;
                float x2 = -_HalfWidth_PitchAndRoll * 0.3f;
                float y1 = 0, y2 = 0;
                g.DrawLine(_RedIndicatorPen, x1, y1, x2, y2);

                x1 = _HalfWidth_PitchAndRoll * 0.65f;
                x2 = _HalfWidth_PitchAndRoll * 0.3f;
                g.DrawLine(_RedIndicatorPen, x1, y1, x2, y2);

                x1 = -_HalfWidth_PitchAndRoll * 0.15f;
                y1 = _HalfHeight_PitchAndRoll * 0.12f;
                x2 = 0;
                y2 = 0;
                g.DrawLine(_RedIndicatorPen, x1, y1, x2, y2);

                x1 = _HalfWidth_PitchAndRoll * 0.15f;
                y1 = _HalfHeight_PitchAndRoll * 0.12f;
                x2 = 0;
                y2 = 0;
                g.DrawLine(_RedIndicatorPen, x1, y1, x2, y2);
                g.ResetTransform();

                // 设置外形为圆角矩形
                GraphicsPath roundRect = new GraphicsPath();
                // 绘制圆角
                rect = new Rectangle(0, 0, width, height);
                roundRect.AddEllipse(rect);
                roundRect.AddRectangle(rect);
                g.FillRegion(new SolidBrush(this.BackColor), new Region(roundRect));
            }
        }

        private void DrawSpeed()
        {
            int
               width = _SpeedBmp.Width,
               height = _SpeedBmp.Height,
               halfWidth = _SpeedBmp.Width / 2,
               halfHeight = _SpeedBmp.Height / 2;

            float speed;
            if (UseAirSpeed)
                speed = (float)AirSpeed;
            else
                speed = (float)GroundSpeed;

            using (Graphics g = Graphics.FromImage(_SpeedBmp))
            {
                g.SmoothingMode = SmoothingMode.AntiAlias;
                g.InterpolationMode = InterpolationMode.NearestNeighbor;
                g.CompositingMode = CompositingMode.SourceOver;
                g.CompositingQuality = CompositingQuality.HighSpeed;
                g.PixelOffsetMode = PixelOffsetMode.HighSpeed;
                g.TextRenderingHint = TextRenderingHint.SystemDefault;

                //g.Clear(Color.FromArgb(128,255,255,255));
                g.Clear(_PanelColor);

                PointF[] line = new PointF[2];
                PointF[] polygon;
                string str;

                StringFormat format = StringFormat.GenericTypographic;
                GraphicsPath path = new GraphicsPath();


                g.TranslateTransform(0, halfHeight + speed * _SpeedIndicatorInterval);

                int centerY = (int)(-speed * _SpeedIndicatorInterval);
                int topY = centerY - halfHeight;
                int bottomY = centerY + halfHeight;

                int start = (int)speed - 4;
                int end = start + 8;
                SizeF strSize = g.MeasureString(end.ToString(), _SmallFont);
                float size = g.DpiY * _SmallFont.SizeInPoints / 72;
                RectangleF rectf;
                for (int i = start; i <= end; i++)
                {
                    line[0] = new PointF(width - _MinLength * 0.03f, -i * _SpeedIndicatorInterval);
                    line[1] = new PointF(_MinLength, -i * _SpeedIndicatorInterval);
                    g.DrawLine(_WhiteIndicatorPen, line[0], line[1]);

                    if (i >= 0 && i % 2 == 0)
                    {
                        strSize = g.MeasureString(i.ToString(), _SmallFont);
                        rectf = new RectangleF(width - _MinLength * 0.04f - strSize.Width, -i * _SpeedIndicatorInterval - strSize.Height / 2, strSize.Width, strSize.Height);
                        path.AddString(i.ToString(), _SmallFont.FontFamily, (int)_SmallFont.Style, size, rectf, format);
                        g.DrawPath(new Pen(Color.Black, 2), path);
                        g.FillPath(Brushes.White, path);
                    }
                }

                // 绘制设置速度
                float basePointY;
                float indicatorHeight;
                float indicatorWidth;

                g.ResetTransform();
                g.TranslateTransform(0, halfHeight);
                strSize = g.MeasureString(speed.ToString(), _MediumFont);
                // 绘制速度读数
                indicatorHeight = _MinLength * 0.04f;
                indicatorWidth = _MinLength * 0.1f;
                basePointY = 0;

                polygon = new PointF[8];
                polygon[0] = new PointF(width - (_MinLength * 0.03f + 3), 0);
                polygon[1] = new PointF(width - (_MinLength * 0.05f + 3), basePointY - indicatorHeight / 3);
                polygon[2] = new PointF(width - (_MinLength * 0.05f + 3), basePointY - indicatorHeight);
                //polygon[3] = new PointF(width - (_MinLength * 0.05f + 3 + strSize.Width * 1.25f), basePointY - indicatorHeight);
                polygon[3] = new PointF(5, basePointY - indicatorHeight);
                //polygon[4] = new PointF(width - (_MinLength * 0.05f + 3 + strSize.Width * 1.25f), basePointY + indicatorHeight);
                polygon[4] = new PointF(5, basePointY + indicatorHeight);
                polygon[5] = new PointF(width - (_MinLength * 0.05f + 3), basePointY + indicatorHeight);
                polygon[6] = new PointF(width - (_MinLength * 0.05f + 3), basePointY + indicatorHeight / 3);
                polygon[7] = new PointF(width - (_MinLength * 0.03f + 3), 0);
                g.FillPolygon(Brushes.Black, polygon);
                //g.FillPolygon(Brushes.Red, polygon);
                g.DrawLines(_WhiteIndicatorPen, polygon);
                g.DrawString($"{((int)speed).ToString()}", _MediumFont, Brushes.White, (width - (_MinLength * 0.05f + 3) + 5 - strSize.Width) / 2, -(int)(strSize.Height / 2.0f));

                g.ResetTransform();

                if (UseAirSpeed)
                {
                    str = "AS\r\nm/s";
                    
                }
                else
                {
                    str = "GS\r\nm/s";
                }
                strSize = g.MeasureString(str, _SmallFont);
                rectf = new RectangleF(3, 3, strSize.Width, strSize.Height);
                path = new GraphicsPath();
                path.AddString(str, _SmallFont.FontFamily, (int)_SmallFont.Style, size, rectf, format);
                g.DrawPath(new Pen(Color.Black, 2), path);
                g.FillPath(Brushes.White, path);
            }
        }

        private void DrawAltitude()
        {
            int
               width = _AltitudeBmp.Width,
               height = _AltitudeBmp.Height;
            //   halfWidth = _AltitudeBmp.Width / 2,
            //   halfHeight = _AltitudeBmp.Height / 2;

            float altitude;
            if (UseRelativeAltitude)
                altitude = RelativeAltitude;
            else
                altitude = AbsoluteAltitude;

            using (Graphics g = Graphics.FromImage(_AltitudeBmp))
            {
                g.SmoothingMode = SmoothingMode.AntiAlias;
                g.InterpolationMode = InterpolationMode.NearestNeighbor;
                g.CompositingMode = CompositingMode.SourceOver;
                g.CompositingQuality = CompositingQuality.HighSpeed;
                g.PixelOffsetMode = PixelOffsetMode.HighSpeed;
                g.TextRenderingHint = TextRenderingHint.SystemDefault;

                //g.Clear(Color.FromArgb(128,255,255,255));
                g.Clear(_PanelColor);

                PointF[] line = new PointF[2];
                PointF[] polygon;
                string str;

                StringFormat format = StringFormat.GenericTypographic;
                GraphicsPath path = new GraphicsPath();


                g.TranslateTransform(0, _HalfHeight_Altitude + altitude * _AltitudeIndicatorInterval);

                int centerY = (int)(-altitude * _SpeedIndicatorInterval);
                int topY = (int)(centerY - _HalfHeight_Altitude);
                int bottomY = (int)(centerY + _HalfHeight_Altitude);

                int start = (int)altitude - 4;
                int end = start + 8;
                SizeF strSize = g.MeasureString("-123", _SmallFont);
                float size = g.DpiY * _SmallFont.SizeInPoints / 72;
                RectangleF rectf;
                for (int i = start; i <= end; i++)
                {
                    line[0] = new PointF(0, -i * _SpeedIndicatorInterval);
                    line[1] = new PointF(_MinLength * 0.03f, -i * _SpeedIndicatorInterval);
                    g.DrawLine(_WhiteIndicatorPen, line[0], line[1]);

                    if (i % 2 == 0)
                    {
                        //MessageBox.Show(i.ToString("D3"));
                        rectf = new RectangleF(_MinLength * 0.04f +3, -i * _SpeedIndicatorInterval - strSize.Height / 2, strSize.Width, strSize.Height);
                        path.AddString(i.ToString(), _SmallFont.FontFamily, (int)_SmallFont.Style, size, rectf, format);
                        g.DrawPath(new Pen(Color.Black, 2), path);
                        g.FillPath(Brushes.White, path);
                    }
                }

                // 绘制设置速度
                float basePointY;
                float indicatorHeight;
                float indicatorWidth;

                g.ResetTransform();
                g.TranslateTransform(0, _HalfHeight_Altitude);
                strSize = g.MeasureString(((int)altitude).ToString(), _MediumFont);
                // 绘制速度读数
                indicatorHeight = _MinLength * 0.04f;
                indicatorWidth = _MinLength * 0.1f;
                basePointY = 0;

                polygon = new PointF[8];
                polygon[0] = new PointF(_MinLength * 0.03f + 3, 0);
                polygon[1] = new PointF(_MinLength * 0.05f + 3, basePointY - indicatorHeight / 3);
                polygon[2] = new PointF(_MinLength * 0.05f + 3, basePointY - indicatorHeight);
                polygon[3] = new PointF(width- 5, basePointY - indicatorHeight);
                polygon[4] = new PointF(width- 5, basePointY + indicatorHeight);
                polygon[5] = new PointF(_MinLength * 0.05f + 3, basePointY + indicatorHeight);
                polygon[6] = new PointF(_MinLength * 0.05f + 3, basePointY + indicatorHeight / 3);
                polygon[7] = new PointF(_MinLength * 0.03f + 3, 0);
                g.FillPolygon(Brushes.Black, polygon);
                g.DrawLines(_WhiteIndicatorPen, polygon);
                g.DrawString($"{((int)altitude).ToString()}", _MediumFont, Brushes.White, (_MinLength * 0.05f + 3 + width - 5- strSize.Width ) / 2 , -(int)(strSize.Height / 2.0f));

                g.ResetTransform();

                if (UseRelativeAltitude)
                {
                    str = "RLT\r\n  m";

                }
                else
                {
                    str = "MSL\r\n  m";
                }
                strSize = g.MeasureString(str, _SmallFont);
                rectf = new RectangleF(width-strSize.Width-3, 3, strSize.Width, strSize.Height);
                path = new GraphicsPath();
                path.AddString(str, _SmallFont.FontFamily, (int)_SmallFont.Style, size, rectf, format);
                g.DrawPath(new Pen(Color.Black, 2), path);
                g.FillPath(Brushes.White, path);
            }
        }

        private void DrawVerticalSpeed()
        {
            int
               width = _VerticalSpeedBmp.Width,
               height = _VerticalSpeedBmp.Height;

            using (Graphics g = Graphics.FromImage(_VerticalSpeedBmp))
            {
                g.SmoothingMode = SmoothingMode.AntiAlias;
                g.InterpolationMode = InterpolationMode.NearestNeighbor;
                g.CompositingMode = CompositingMode.SourceOver;
                g.CompositingQuality = CompositingQuality.HighSpeed;
                g.PixelOffsetMode = PixelOffsetMode.HighSpeed;
                g.TextRenderingHint = TextRenderingHint.SystemDefault;

                float indicatorWidth = width * 0.7f;
                float indicatorWidth2 = width * 0.5f;
                float indicatorHeight2 = height * 0.15f;
                PointF[] polygon = new PointF[7];
                polygon[0] = new PointF(0, 0);
                polygon[1] = new PointF(indicatorWidth2, 0);
                polygon[2] = new PointF(indicatorWidth, height / 2 - indicatorHeight2);
                polygon[3] = new PointF(indicatorWidth, height / 2 + indicatorHeight2);
                polygon[4] = new PointF(indicatorWidth2, height);
                polygon[5] = new PointF(0, height);
                polygon[6] = new PointF(0, 0);
                g.Clear(Color.Transparent);
                g.FillPolygon(_PanelBrush, polygon);

                g.TranslateTransform(0, height / 2f);

                PointF[] line = new PointF[2];
                int gap = Math.Max(width, height) / 10 - 2;

                line[0] = new PointF(indicatorWidth, 0);
                if (_VerticalSpeed > 5)
                    line[1] = new PointF(indicatorWidth2, -gap * 5);
                else if (_VerticalSpeed < -5)
                    line[1] = new PointF(indicatorWidth2, -gap * -5);
                else
                    line[1] = new PointF(indicatorWidth2, -gap * _VerticalSpeed);
                g.DrawLine(_RedIndicatorPen, line[0], line[1]);



                indicatorWidth = width * 0.3f;
                indicatorWidth2 = width * 0.4f;
                SizeF strSize = g.MeasureString("8", _SmallFont);
                StringFormat format = StringFormat.GenericTypographic;
                GraphicsPath path = new GraphicsPath();
                RectangleF rectf;//= new RectangleF(5, -strSize.Height / 2, strSize.Width, strSize.Height);
                float size = g.DpiY * _SmallFont.SizeInPoints / 72;
                for (int i = 0; i < 6; i++)
                {
                    line[0] = new PointF(indicatorWidth, i * gap);
                    line[1] = new PointF(indicatorWidth2, i * gap);
                    g.DrawLine(_WhiteIndicatorPen, line[0], line[1]);

                    line[0] = new PointF(indicatorWidth, -i * gap);
                    line[1] = new PointF(indicatorWidth2, -i * gap);
                    g.DrawLine(_WhiteIndicatorPen, line[0], line[1]);

                    rectf = new RectangleF(2, i * gap - strSize.Height / 2, strSize.Width, strSize.Height);
                    path.AddString(i.ToString(), _SmallFont.FontFamily, (int)_SmallFont.Style, size, rectf, format);

                    if (i != 0)
                    {
                        rectf = new RectangleF(2, -i * gap - strSize.Height / 2, strSize.Width, strSize.Height);
                        path.AddString((i).ToString(), _SmallFont.FontFamily, (int)_SmallFont.Style, size, rectf, format);
                    }

                    g.DrawPath(new Pen(Color.Black, 2), path);
                    g.FillPath(Brushes.White, path);
                }


            }
        }

        private void DrawCompass()
        {
            int
               width = _CompassBmp.Width,
               height = _CompassBmp.Height,
               halfWidth = _CompassBmp.Width / 2,
               halfHeight = _CompassBmp.Height / 2;

            int _Min = 0, _Max = 360;

            using (Graphics g = Graphics.FromImage(_CompassBmp))
            {
                g.SmoothingMode = SmoothingMode.AntiAlias;
                g.InterpolationMode = InterpolationMode.NearestNeighbor;
                g.CompositingMode = CompositingMode.SourceOver;
                g.CompositingQuality = CompositingQuality.HighSpeed;
                g.PixelOffsetMode = PixelOffsetMode.HighSpeed;
                g.TextRenderingHint = TextRenderingHint.SystemDefault;

                g.Clear(_PanelColor);

                PointF[] polygon = new PointF[3];
                float triangleWidth = width * 0.015f;
                float triangleHeight = (float)(triangleWidth * Math.Tan(Math.PI / 3));
                polygon[0] = new PointF(width / 2, triangleHeight);
                polygon[1] = new PointF(width / 2 - triangleWidth, 2);
                polygon[2] = new PointF(width / 2 + triangleWidth, 2);

                g.DrawPolygon(_WhiteIndicatorPen, polygon);
                g.FillPolygon(Brushes.Red, polygon);

                float offset = (float)(_Heading - (int)_Heading);
                float start = width / 2 - offset * _CompassIndicatorInterval;
                PointF[] line = new PointF[2];
                float x;
                float size = g.DpiY * _SmallFont.SizeInPoints / 72;
                StringFormat format = StringFormat.GenericTypographic;
                for (int i = 0; i < width / (_CompassIndicatorInterval / 2); i++)
                {
                    x = i * _CompassIndicatorInterval / 2;
                    line[0] = new PointF(start + i * _CompassIndicatorInterval / 2, 10);
                    line[1] = new PointF(start + i * _CompassIndicatorInterval / 2, 17);
                    g.DrawLine(_WhiteIndicatorPen, line[0], line[1]);

                    line[0] = new PointF(start - i * _CompassIndicatorInterval / 2, 10);
                    line[1] = new PointF(start - i * _CompassIndicatorInterval / 2, 17);
                    g.DrawLine(_WhiteIndicatorPen, line[0], line[1]);

                    if (i % 2 == 0)
                    {
                        int h;

                        if (_Heading >= 0)
                            h = (int)Math.Floor(_Heading + i / 2);
                        else
                            h = (int)Math.Ceiling(_Heading + i / 2);


                        while (h < _Min)
                            h = _Max - (_Min - h);
                        while (h > _Max)
                            h = _Min + h - _Max;
                        if (h == _Max)
                            h = _Min;

                        var strSize = g.MeasureString(h.ToString(), _SmallFont);
                        RectangleF rectf = new RectangleF(start + i * _CompassIndicatorInterval / 2 - strSize.Width / 2, 19, strSize.Width, strSize.Height);
                        GraphicsPath path = new GraphicsPath();
                        path.AddString(h.ToString(), _SmallFont.FontFamily, (int)_SmallFont.Style, size, rectf, format);

                        g.DrawPath(new Pen(Color.Black, 2), path);
                        g.FillPath(Brushes.White, path);


                        if (_Heading >= 0)
                            h = (int)Math.Floor(_Heading - i / 2);
                        else
                            h = (int)Math.Ceiling(_Heading - i / 2);

                        while (h < _Min)
                            h = _Max - (_Min - h);
                        while (h > _Max)
                            h = _Min + h - _Max;
                        if (h == _Max)
                            h = _Min;
                        if (h != 0)
                        {
                            strSize = g.MeasureString(h.ToString(), _SmallFont);
                            rectf = new RectangleF(start - i * _CompassIndicatorInterval / 2 - strSize.Width / 2, 19, strSize.Width, strSize.Height);
                            path.AddString(h.ToString(), _SmallFont.FontFamily, (int)_SmallFont.Style, size, rectf, format);

                            g.DrawPath(new Pen(Color.Black, 2), path);
                            g.FillPath(Brushes.White, path);
                        }
                    }
                }

                g.ResetTransform();

            }
        }















        private void PaintMiniMode(PaintEventArgs e)
        {
            using (Bitmap bmp = new Bitmap(this.Width, this.Height))
            {
                using (Graphics g = Graphics.FromImage(bmp))
                {
                    g.Clear(Color.Transparent);

                    DrawMiniPitchAndRoll();
                    g.DrawImage(_PitchAndRollBmp, _PitchAndRollLocation);
                }

                e.Graphics.DrawImage(bmp, 0, 0);
            }
        }

        private void PaintFullMode(PaintEventArgs e)
        {
            using (Bitmap bmp = new Bitmap(this.Width, this.Height))
            {
                using (Graphics g = Graphics.FromImage(bmp))
                {
                    g.Clear(BackColor);


                    DrawPitchAndRoll();
                    g.DrawImage(_PitchAndRollBmp, _PitchAndRollLocation);

                    DrawAltitude();
                    g.DrawImage(_AltitudeBmp, _AltitudeLocation);

                    DrawSpeed();
                    g.DrawImage(_SpeedBmp, _SpeedLocation);

                    DrawVerticalSpeed();
                    g.DrawImage(_VerticalSpeedBmp, _VerticalSpeedLocation);

                    DrawCompass();
                    g.DrawImage(_CompassBmp, _CompassLocation);
                }

                e.Graphics.DrawImage(bmp, 0, 0);
            }
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            if (MiniMode)
            {
                PaintMiniMode(e);
                Rectangle rect = new Rectangle(0, 0, _PitchAndRollBmp.Width, _PitchAndRollBmp.Height);
                GraphicsPath roundRect = new GraphicsPath();
                roundRect.AddEllipse(_PitchAndRollLocation.X, _PitchAndRollLocation.Y, _PitchAndRollBmp.Width, _PitchAndRollBmp.Height);
                this.Region = new Region(roundRect);
            }
            else
            {
                PaintFullMode(e);

                if (RoundCorner) 
                {
                    // 绘制圆角
                    Rectangle rect = new Rectangle(0, 0, this.Width, this.Height);
                    int radius = (int)(_MinLength / 10);
                    GraphicsPath roundRect = new GraphicsPath();
                    //顶端 
                    roundRect.AddLine(rect.Left + radius - 1, rect.Top - 1, rect.Right - radius, rect.Top - 1);
                    //右上角 
                    roundRect.AddArc(rect.Right - radius, rect.Top - 1, radius, radius, 270, 90);
                    //右边 
                    roundRect.AddLine(rect.Right, rect.Top + radius, rect.Right, rect.Bottom - radius);
                    //右下角
                    roundRect.AddArc(rect.Right - radius, rect.Bottom - radius, radius, radius, 0, 90);
                    //底边 
                    roundRect.AddLine(rect.Right - radius, rect.Bottom, rect.Left + radius, rect.Bottom);
                    //左下角 
                    roundRect.AddArc(rect.Left - 1, rect.Bottom - radius, radius, radius, 90, 90);
                    //左边 
                    roundRect.AddLine(rect.Left - 1, rect.Top + radius, rect.Left - 1, rect.Bottom - radius);
                    //左上角 
                    roundRect.AddArc(rect.Left - 1, rect.Top - 1, radius, radius, 180, 90);

                    this.Region = new Region(roundRect);
                }
                else
                {
                    this.Region = new Region(new RectangleF(0, 0, this.Width, this.Height));
                }
                
            }


            base.OnPaint(e);
        }
    }
}
